package cn.iocoder.yudao.module.mybusiness.service.impl;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mybusiness.domain.BussinessMod;
import cn.iocoder.yudao.module.mybusiness.domain.Facility;
import cn.iocoder.yudao.module.mybusiness.domain.Job;
import cn.iocoder.yudao.module.mybusiness.domain.Task;
import cn.iocoder.yudao.module.mybusiness.mapper.FacilityMapper;
import cn.iocoder.yudao.module.mybusiness.mapper.ModMapper;
import cn.iocoder.yudao.module.mybusiness.mapper.RecordMapper;
import cn.iocoder.yudao.module.mybusiness.mapper.TaskMapper;
import cn.iocoder.yudao.module.mybusiness.param.TaskParam;
import cn.iocoder.yudao.module.mybusiness.service.TaskService;
import cn.iocoder.yudao.module.mybusiness.util.TaskExecute;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TaskServiceImpl  extends ServiceImpl<TaskMapper, Task> implements TaskService {

    @Autowired
    private ModMapper modMapper;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private RecordMapper recordMapper;

    @Autowired
    private FacilityMapper facilityMapper;

    @Override
    public PageResult<Task> getList(TaskParam taskParam) {
        PageResult<Task> taskPageResult = taskMapper.selectPage(taskParam, new LambdaQueryWrapperX<Task>()
                .eq(Task::getIsDelete, 0)
                .likeIfPresent(Task::getName, taskParam.getName())
                .eqIfPresent(Task::getResult, taskParam.getResult())
                .orderByAsc(Task::getResult)
                .orderByDesc(Task::getId));

        if(taskPageResult != null && taskPageResult.getTotal()>0){
            taskPageResult.getList().forEach(task -> {
                double percentage = ((double) task.getAccomplishNum() / task.getTaskNums()) * 100;
                // 格式化输出百分比，保留两位小数
                DecimalFormat formatter = new DecimalFormat("#0");
                String formattedPercentage = formatter.format(percentage);
                task.setSchedule(Integer.valueOf(formattedPercentage));
                task.setFcfList(JSONObject.parseArray(task.getFcfIds(),List.class));
                List<Map> lists = JSONObject.parseArray(task.getModsJson(), Map.class);
                task.setModJsonList(lists);
            });
        }
        return taskPageResult;
    }

    @Override
    public void delete(Long id) throws Exception {
        Task task = taskMapper.selectById(id);
        if(task.getResult() ==1){
            throw new Exception("任务执行中无法删除");
        }
        taskMapper.logicDel(id);
    }

    @Override
    public void create(Task task) {
        List<BussinessMod> bussinessMods = modMapper.selectList(new LambdaQueryWrapperX<BussinessMod>().eq(BussinessMod::getIsDelete, 0));
        Map<Long, Integer> collect = bussinessMods.stream().collect(Collectors.toMap(BussinessMod::getId, BussinessMod::getWorkTime));
        List<Map> modJsonList = task.getModJsonList();

        //设备集合
        List fcfList = new ArrayList();
        List<List> fcfIds = task.getFcfList();
        fcfIds.forEach(list1 -> {
            fcfList.add(list1.get(1));
        });
        List<Job> jobList = new ArrayList();
        modJsonList.forEach(map->{
            Long num = Long.valueOf(String.valueOf(map.get("num")));  //数量
            long modId = Long.valueOf(String.valueOf(map.get("modId")));
            for (int i = 0; i < num; i++) {
                jobList.add(new Job(i+1,collect.get(modId),modId));
            }
        });

        //分配个机器工作时间
        Map<String,List<Job>> map = this.distributionJob(fcfList.size(), jobList);
        List<List<Job>> workTimes = map.values().stream().collect(Collectors.toList());

        //保存任务
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        task.setCreateTime(format.format(new Date()));
        task.setResult(1);
        task.setModsJson(JSONObject.toJSONString(task.getModJsonList()));
        task.setFcfIds(JSONObject.toJSONString(task.getFcfList()));
        task.setTaskNums(jobList.size());
        taskMapper.insertTask(task);

        Collections.shuffle(fcfList);
        ExecutorService executorService = Executors.newFixedThreadPool(fcfList.size());

        //开始生产
        for (int i = 0; i < workTimes.size(); i++) {
            Facility facility = facilityMapper.selectById(Long.valueOf(String.valueOf(fcfList.get(i))));
            TaskExecute taskExecute = new TaskExecute(Long.valueOf(String.valueOf(fcfList.get(i))), workTimes.get(i), taskMapper, recordMapper,facilityMapper, task.getId(),facility.getCraft());
            executorService.execute(taskExecute);
        }
        executorService.shutdown();
    }

    public Map distributionJob(int numMachines,List<Job> jobs){
        // 对作业按处理时间进行排序（SPT）
        Collections.sort(jobs);
        System.out.println(JSONObject.toJSONString(jobs));
        Map<String,List> map = new HashMap();
        // 机器的工作时间列表，初始化为0  
        int[] machineTimes = new int[numMachines];

        // 分配作业到机器  
        for (Job job : jobs) {
            // 找到当前负载最小的机器  
            int minMachineIndex = 0;
            for (int i = 1; i < numMachines; i++) {
                if (machineTimes[i] < machineTimes[minMachineIndex]) {
                    minMachineIndex = i;
                }
            }
            // 将作业分配给该机器，并更新该机器的工作时间
            machineTimes[minMachineIndex] += job.getProcessingTime();
            String machineId = "machine " + (minMachineIndex + 1);
            if(map.containsKey(machineId)){
                List o = map.get(machineId);
                o.add(job);
            }else{
                List list2 = new ArrayList();
                list2.add(job);
                map.put(machineId,list2);
            }
            // 打印当前机器的工作时间和已分配的作业  
            System.out.println("Assigned job " + job.getId() + " with processing time " + job.getProcessingTime() +
                    " to machine " + (minMachineIndex + 1) +
                    " with total time now " + machineTimes[minMachineIndex]);
        }

        // 打印所有机器的最终工作时间  
        System.out.println("Final machine times:");
        for (int i = 0; i < numMachines; i++) {
            System.out.println("Machine " + (i + 1) + ": " + machineTimes[i]);
        }
        return map;
    }
}
